package it.antonio.ilpizze.reflection;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;

public class FieldAccessor {
	private Field field;

	public FieldAccessor(Field field) {
		super();
		this.field = field;
		if (!this.field.isAccessible()) {
			field.setAccessible(true);
		}
	}

	public void set(Object instance, Object value) {
		try {
			field.set(instance, value);
		} catch (IllegalArgumentException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			throw new ReflectionException(e.getMessage(), e);
		}
	}

	public Object get(Object instance) {
		try {
			return field.get(instance);
		} catch (IllegalArgumentException e) {
			throw new ReflectionException(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			throw new ReflectionException(e.getMessage(), e);
		}
	}

	public <T extends Annotation> T getAnnotation(Class<T> annotation) {
		return field.getAnnotation(annotation);
	}

	public boolean isAnnotationPresent(Class<? extends Annotation> arg0) {
		return field.isAnnotationPresent(arg0);
	}

	public boolean hasAnnotation(Class<? extends Annotation> annotation) {
		return field.isAnnotationPresent(annotation);
	}

	public List<Annotation> getAnnotations() {
		return Arrays.asList(field.getAnnotations());
	}

	public Class<?> getType() {
		return field.getType();
	}

	public Clazz<?> getClazz() {
		return Clazz.get(field.getType());
	}

	public String getName() {
		return field.getName();
	}

	public boolean isStatic() {
		return Modifier.isStatic(field.getModifiers());
	}
	
	@Override
	public boolean equals(Object o) {
		if(o instanceof FieldAccessor){
			FieldAccessor f = (FieldAccessor) o;
			return f.field.equals(field);
		}
		if(o instanceof Field){
			Field f = (Field) o;
			return f.equals(field);
		}
		return false;
	}

	public Class<?> getDeclaringClass() {
		return field.getDeclaringClass();
	}
	
	@Override
	public String toString() {
		return field.toString();
	}

	public Type getGenericType() {
		return field.getGenericType();
	}
}